theme.js ➔ elk_addButton   F
last analyzed

Complexity

Conditions 30

Size

Total Lines 42
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 30
eloc 27
dl 0
loc 42
rs 0
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like theme.js ➔ elk_addButton often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
 * @package   ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
5
 *
6
 * @version 2.0 dev
7
 */
8
9
/**
10
 * This file contains JavaScript associated with the current theme
11
 */
12
13
// Normal JS document ready event
14
document.addEventListener('DOMContentLoaded', function() {
15
16
	// If they touch the screen, then we switch to click menus
17
	window.addEventListener('touchstart', onFirstTouch, false);
18
19
	// Or if they specifically only want click menus
20
	if (use_click_menu)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable use_click_menu is declared in the current environment, consider using typeof use_click_menu === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
21
	{
22
		useClickMenu();
23
	}
24
25
	// Fix code blocks so they are as compact as possible
26
	if (typeof elk_codefix === 'function')
0 ignored issues
show
Bug introduced by
The variable elk_codefix seems to be never declared. If this is a global, consider adding a /** global: elk_codefix */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
27
	{
28
		elk_codefix();
29
	}
30
31
	if (typeof elk_quotefix === 'function')
0 ignored issues
show
Bug introduced by
The variable elk_quotefix seems to be never declared. If this is a global, consider adding a /** global: elk_quotefix */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
32
	{
33
		elk_quotefix();
34
	}
35
36
	// If you want a sticky menu on scroll, add an appropriate .sticky CSS class to your theme
37
	// This adds / removes a .sticky class on scroll, see index_gold.css for an example.
38
	stickyMenu();
39
40
	// Smooth scroll to top.
41
	document.getElementById('gotop').addEventListener('click', function(e) {
42
		e.preventDefault();
43
		window.scrollTo({top: 0, behavior: 'smooth'});
44
	});
45
46
	// Smooth scroll to bottom.
47
	document.getElementById('gobottom').addEventListener('click', function(e) {
48
		e.preventDefault();
49
50
		// Don't scroll all the way down to the footer, just the content bottom
51
		let link = document.querySelector('#footer_section'),
52
			linkY = link.offsetHeight,
53
			heightDiff = link.getBoundingClientRect().top + linkY - window.innerHeight;
54
55
		window.scrollBy({top: heightDiff, behavior: 'smooth'});
56
	});
57
58
	// Find all nested linked images and turn off the border
59
	let elements = document.querySelectorAll('a.bbc_link img.bbc_img');
60
	for (let i = 0; i < elements.length; i++)
61
	{
62
		let parentElement = elements[i].parentNode;
63
		parentElement.style.border = '0';
64
	}
65
66
	// Expand the moderation hamburger icon/button view for mobile devices
67
	let hamburger = document.querySelector('.hamburger_30');
68
	if (hamburger)
69
	{
70
		hamburger.addEventListener('click', function(e) {
71
			let id = this.getAttribute('data-id');
72
			e.preventDefault();
73
			document.getElementById(id).classList.add('visible');
74
			this.classList.add('visible');
75
		});
76
	}
77
78
	// Collapsible fieldsets, pure candy
79
	document.querySelector('body').addEventListener('click', function(event) {
80
		if (event.target.matches('legend'))
81
		{
82
			let siblings = elkGetSiblings(event.target);
83
			siblings.forEach(sib => sib.slideToggle());
84
			event.target.parentNode.classList.toggle('collapsed');
85
		}
86
	});
87
88
	// For any legends with data-collapsed="true", start them collapsed
89
	document.querySelectorAll('legend').forEach(function(el) {
90
		if (el.getAttribute('data-collapsed') !== null)
91
		{
92
			el.click();
93
		}
94
	});
95
96
	// Spoiler
97
	document.querySelectorAll('.spoilerheader').forEach(element => {
98
		element.addEventListener('click', function() {
99
			element.nextElementSibling.children[0].slideToggle(250);
100
		});
101
	});
102
});
103
104
// Jquery document ready
105
$(function() {
106
	// Enable the ... page expansion
107
	$('.expand_pages').expand_pages();
108
109
	// Attachment thumbnail expands on click
110
	// You can remove this namespaced click with $('[data-lightboximage]').off('click.elk_lb');
111
	$('[data-lightboximage]').on('click.elk_lb', function(e) {
112
		e.preventDefault();
113
		expandThumbLB($(this).data('lightboximage'), $(this).data('lightboxmessage'));
114
	});
115
116
	// BBC image inline expand on click.
117
	// You can turn off this namespaced click event with $('[data-bbcexpandimage]').off("click.elk_bbc")
118
	$('[data-bbcexpandimage]').on('click.elk_bbc', function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
119
		let $this = $(this);
120
121
		// No saved data, then set it to auto expand
122
		if ($.isEmptyObject($this.data('bbc_img')))
123
		{
124
			$this.data('bbc_img', {
125
				width: $this.css('width'),
126
				height: $this.css('height'),
127
				'max-width': $this.css('max-width'),
128
				'max-height': $this.css('max-height'),
129
			});
130
			$this.css({'width': $this.css('width') === 'auto' ? null : 'auto'});
131
			$this.css({'height': $this.css('height') === 'auto' ? null : 'auto'});
132
133
			// Override default css to allow the image to expand fully, add a div to expand in
134
			$this.css({'max-height': 'none'});
135
			$this.css({'max-width': '100%'});
136
			$this.wrap('<div style="overflow:auto;display:inline-block;"></div>');
137
		}
138
		else
139
		{
140
			// Was previously clicked and saved, so set it back
141
			$this.css({'width': $this.data('bbc_img').width});
142
			$this.css({'height': $this.data('bbc_img').height});
143
			$this.css({'max-width': $this.data('bbc_img')['max-width']});
144
			$this.css({'max-height': $this.data('bbc_img')['max-height']});
145
146
			// Remove the data
147
			$this.removeData('bbc_img');
148
149
			// Remove the div we added to allow the image to overflow expand in
150
			$this.unwrap();
151
			$this.css({'max-width': '100%'});
152
		}
153
	});
154
});
155
156
/**
157
 * Adds a button to the quick topic moderation after a checkbox is selected
158
 *
159
 * @param {string} sButtonStripId
160
 * @param {boolean} bUseImage
161
 * @param {object} oOptions
162
 */
163
function elk_addButton (sButtonStripId, bUseImage, oOptions)
164
{
165
	let oButtonStrip = document.getElementById(sButtonStripId),
166
		aItems = oButtonStrip.getElementsByTagName('span');
167
168
	// Remove the 'last' class from the last item.
169
	if (aItems.length > 0)
170
	{
171
		let oLastSpan = aItems[aItems.length - 1];
172
		oLastSpan.className = oLastSpan.className.replace(/\s*last/, 'position_holder');
173
	}
174
175
	// Add the button.
176
	let oButtonStripList = oButtonStrip.getElementsByTagName('ul')[0],
177
		oNewButton = document.createElement('li'),
178
		oRole = document.createAttribute('role');
179
180
	oRole.value = 'menuitem';
181
	oNewButton.setAttributeNode(oRole);
182
183
	if ('sId' in oOptions)
184
	{
185
		oNewButton.id = oOptions.sId;
186
	}
187
188
	oNewButton.innerHTML = '' +
189
		'<a class="linklevel1" href="' + oOptions.sUrl + '" ' + ('sCustom' in oOptions ? oOptions.sCustom : '') + '>' +
190
		('sImage' in oOptions && bUseImage ? '<i class="icon ' + oOptions.sImage + '"></i>' : '') +
191
		'   <span class="last"' + ('sId' in oOptions ? ' id="' + oOptions.sId + '_text"' : '') + '>' +
192
		oOptions.sText +
193
		'   </span>' +
194
		'</a>';
195
196
	if (oOptions.aEvents)
197
	{
198
		oOptions.aEvents.forEach(function(e) {
199
			oNewButton.addEventListener(e[0], e[1]);
200
		});
201
	}
202
203
	oButtonStripList.appendChild(oNewButton);
204
}
205
206
// Get your paws off me
207
function onFirstTouch ()
208
{
209
	useClickMenu();
210
}
211
212
// Activates click menus when a touch event is detected.
213
function useClickMenu ()
214
{
215
    // Click Menu drop downs
216
    let menus = ['#main_menu', '#sort_by', 'ul.poster', 'ul.quickbuttons', 'ul.admin_menu', 'ul.sidebar_menu', 'ul.buttonlist'];
217
218
    menus.forEach((selector) => {
219
        // Initialize each matching element individually so all instances work (e.g., multiple quickbuttons)
220
        let nodes = document.querySelectorAll(selector);
221
        if (nodes && nodes.length)
222
        {
223
            Array.prototype.forEach.call(nodes, function(node) {
224
                new elkMenu(node);
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like elkMenu should be capitalized.
Loading history...
Bug introduced by
The variable elkMenu seems to be never declared. If this is a global, consider adding a /** global: elkMenu */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Unused Code Best Practice introduced by
The object created with new elkMenu(node) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
225
            });
226
        }
227
        else
228
        {
229
            // For unique selectors (like IDs), try initializing once by selector
230
            new elkMenu(selector);
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like elkMenu should be capitalized.
Loading history...
Unused Code Best Practice introduced by
The object created with new elkMenu(selector) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
Bug introduced by
The variable elkMenu seems to be never declared. If this is a global, consider adding a /** global: elkMenu */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
231
        }
232
    });
233
234
    window.removeEventListener('touchstart', onFirstTouch, false);
235
}
236
237
// Adds/Removes sticky class to id='menu_nav'
238
function stickyMenu ()
239
{
240
	let menu = document.getElementById('menu_nav');
241
242
	if (menu)
243
	{
244
		let offset = menu.getBoundingClientRect().y;
245
		window.onscroll = function() {
246
			if (window.scrollY > offset - 5)
247
			{
248
				menu.classList.add('sticky');
249
			}
250
			else if (window.scrollY < offset - 20)
251
			{
252
				menu.classList.remove('sticky');
253
			}
254
		};
255
	}
256
}
257